package com.baofu.paycore.service;

import com.baofu.paycore.biz.model.BackPayBO;
import com.baofu.paycore.biz.model.WebPayBO;
import com.baofu.paycore.biz.paycore.handler.impl.ConsumeHandler;
import com.baofu.paycore.biz.paycore.handler.impl.WebConsumerHandler;
import com.baofu.paycore.common.utils.ExceptionUtil;
import com.baofu.paycore.manager.model.PayBO;
import com.baofu.paycore.manager.storer.PayOrderRepository;
import com.baofu.paycore.service.converter.BO2DTOConverter;
import com.baofu.paycore.service.facade.PayServiceFacade;
import com.baofu.paycore.service.facade.enums.PayStatusEnums;
import com.baofu.paycore.service.facade.model.PayConfirmReqDTO;
import com.baofu.paycore.service.facade.model.PayResDTO;
import com.baofu.paycore.service.facade.model.WebPayResDTO;
import com.baofu.paycore.service.facade.model.pay.PayDTO;
import com.baofu.paycore.service.factory.impl.ConsumeFactoryImpl;
import com.baofu.paycore.service.validate.impl.consume.ConsumeConfirmValidate;
import com.baofu.paycore.service.validate.impl.consume.ConsumeValidate;
import com.system.commons.result.Result;
import com.system.commons.utils.ParamValidate;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.slf4j.helpers.SystemMarker;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;

/**
 * 消费类服务 service
 *
 * <ul>
 *     <li>1.跳转外部支付渠道进行消费</li>
 *     <li>2.外部支付渠道支付完成后异步回调</li>
 *     <li>3.消费支付接口</li>
 *     <li>4.消费撤销接口</li>
 * </ul>
 * User: LZQ  Date: 2014/11/21 ProjectName: paycore Version: 5.0.0
 */
@Slf4j
@Service
public class PayService implements PayServiceFacade {

    /**
     * 统一支付业务处理类
     */
    @Autowired
    private ConsumeHandler consumeHandler;

    /**
     * web支付
     */
    @Autowired
    private WebConsumerHandler webConsumerHandler;

    /**
     * 消费服务参数校验
     */
    @Autowired
    private ConsumeValidate consumeValidate;

    /**
     * 支付模型服务
     */
    @Autowired
    private ConsumeFactoryImpl payBaseFactory;

    /**
     * 支付单存储
     */
    @Resource
    private PayOrderRepository payOrderRepository;

    /**
     * 支付确认校验器
     */
    @Autowired
    private ConsumeConfirmValidate consumeConfirmValidate;

    /**
     * 跳转外部支付渠道进行消费
     *
     * @param payDTO 消费请求对象
     * @return 消费结果
     */
    @Override
    public Result<WebPayResDTO> webPay(PayDTO payDTO, String transLogId) {
        MDC.put(SystemMarker.TRACE_LOG_ID, transLogId);
        long start = System.currentTimeMillis();
        Result<WebPayResDTO> result = null;
        boolean flag = false;
        try {
            log.info("web 支付请求参数, consumeDTO:{}", payDTO);
            flag = consumeValidate.lock(payDTO);
            //1、请求对象参数校验
            consumeValidate.paramsValidate(payDTO);

            result = consumeValidate.validateUniqueOrder(payDTO,payOrderRepository,WebPayResDTO.class) ;
            if(result != null){
                return result;
            }
            //2、请求对象转换
            PayBO payBO = payBaseFactory.build(payDTO);
            payBO.setTradeLogId(transLogId);

            //3、消费相关信息落地
            payOrderRepository.addOrder(payBO);

            //4、业务流程处理
            WebPayBO webPayBO = webConsumerHandler.asyncProcess(payBO);

            //5、接口返回对象生成
            WebPayResDTO webPayResDTO = BO2DTOConverter.getWebPayResDTO(webPayBO,payBO);
            result = new Result<>(webPayResDTO);

        } catch (Exception e) {

            log.error("web 支付异常 error, EXCEPTION:{}", e);
            result = ExceptionUtil.doExceptionService(e,WebPayResDTO.class);
        } finally {
            log.info("web pay 耗时:{} 支付响应:{}",System.currentTimeMillis() - start,result);
            consumeValidate.release(payDTO,flag);
            MDC.clear();
        }
        return result;
    }

    /**
     * 快捷支付（认证支付）接口
     *
     * @param payDTO 消费服务参数
     * @return 消费服务结果
     */
    @Override
    public Result<PayResDTO> pay(PayDTO payDTO, String transLogId) {
        long start = System.currentTimeMillis();
        Result<PayResDTO> result = null;
        boolean flag = false;
        try {
            MDC.put(SystemMarker.TRACE_LOG_ID, transLogId);

            log.info("快捷支付接口请求信息参数：{}", payDTO);

            flag = consumeValidate.lock(payDTO);

            //1、请求对象参数校验
            consumeValidate.paramsValidate(payDTO);
            result = consumeValidate.validateUniqueOrder(payDTO, payOrderRepository, PayResDTO.class);
            if (result != null) {
                PayResDTO payResDTO = result.getResult();
                payResDTO.setRealRtnFlag(payBaseFactory.getRealRtnFlag(payResDTO.getStatus()));
                payResDTO.setRespDate(new Date());
                return result;
            }
            //2、请求对象转换
            PayBO payBO = payBaseFactory.build(payDTO);
            payBO.setTradeLogId(transLogId);

            //3、消费相关信息落地
            payOrderRepository.addOrder(payBO);

            //4、业务流程处理
            BackPayBO backPayBO = consumeHandler.process(payBO);

            //5、接口返回对象生成
            result = new Result<>(BO2DTOConverter.getConsumeResDTO(new PayResDTO(), backPayBO));
        } catch (Exception e) {

            log.error("后台 支付异常 EXCEPTION:{}", e);
            result = ExceptionUtil.doExceptionService(e,PayResDTO.class);
        } finally {
            log.info("back pay 耗时:{} 支付响应:{}",System.currentTimeMillis() - start,result);
            consumeValidate.release(payDTO,flag);
            MDC.clear();
        }
        return result;
    }

    /**
     * 支付确认(快捷)
     * @param payDTO                    请求参数
     * @param transLogId                日志ID
     * @return                          支付结果
     */
    @Override
    public Result<PayResDTO> payConfirm(PayConfirmReqDTO payDTO, String transLogId) {
        long start = System.currentTimeMillis();
        Result<PayResDTO> result = null;
        boolean flag = false;
        try {
            MDC.put(SystemMarker.TRACE_LOG_ID, transLogId);

            log.info("快捷支付确认接口请求信息参数：{}", payDTO);

            flag = consumeConfirmValidate.lock(payDTO);

            //1、请求对象参数校验
            ParamValidate.validateParams(payDTO);

            result = consumeConfirmValidate.validateOrder(payDTO,payOrderRepository,PayResDTO.class) ;
            if(result != null){
                PayResDTO payResDTO = result.getResult();
                payResDTO.setRespDate(new Date());
                payResDTO.setRealRtnFlag(payBaseFactory.getRealRtnFlag(payResDTO.getStatus()));
                return result;
            }

            //2、请求对象转换
            PayBO payBO = payOrderRepository.load(payDTO.getPayNo());
            payBO.setTradeLogId(transLogId);
            payBO.setSmsCode(payDTO.getSmsCode());

            //4、业务流程处理
            BackPayBO backPayBO = consumeHandler.process(payBO);

            //5、接口返回对象生成
            result = new Result<>(BO2DTOConverter.getConsumeResDTO(new PayResDTO(),backPayBO));

        } catch (Exception e) {

            log.error("快捷支付确认接口 EXCEPTION:{}", e);
            result = ExceptionUtil.doExceptionService(e,PayResDTO.class);
        } finally {
            log.info("quick pay confirm 耗时:{} 支付响应:{}",System.currentTimeMillis() - start,result);
            consumeConfirmValidate.release(payDTO,flag);
            MDC.clear();
        }
        return result;
    }

}
